#include "oled.h"
#include "ssd1306_i2c.h"
#include "msgd.h"
#include "temp.h"


static int oledLogLevel = LOG_WARNING;

void initOled()
{
    ssd1306_begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS);
    ssd1306_clearDisplay();
    ssd1306_display();
}

void setOledLogLevel(int logLevel)
{
    oledLogLevel = logLevel;
}

void clear_screen()
{
    ssd1306_clearDisplay();
    ssd1306_display();
}

void getCPUInfo(char * cpuInfo)
{

    char buf_cpu[128];
    char cpu[5];
    FILE * fp_CPUusage;
    float usage;
    long int user, nice, sys, idle, iowait, irq, softirq;
	long int total_1, total_2, idle_1, idle_2;


    fp_CPUusage = fopen(CPU_USAGE_PATH, "r");
    perr_d(fp_CPUusage == NULL,oledLogLevel,"function fopen error when called getCPUInfo");

    /* CPU使用率计算方式：usage = 100*(total-idle/total)
        * 通过两次获取/proc/stat的数据差得到total和idle
    */

    // 第一次读取数据
    fgets(buf_cpu, sizeof(buf_cpu), fp_CPUusage);
    sscanf(buf_cpu,"%s%ld%ld%ld%ld%ld%ld%ld",cpu,&user,&nice,&sys,&idle,&iowait,&irq,&softirq);
    total_1 = user + nice + sys + idle + iowait + irq + softirq;
    idle_1 = idle;
    rewind(fp_CPUusage);

    // 延时并且清空数据
    sleep(1);
    memset(buf_cpu, 0, sizeof(buf_cpu));
    cpu[0] = '\0';
    user = nice = sys = idle = iowait = softirq = 0;

    // 第二次读取数据
    fgets(buf_cpu, sizeof(buf_cpu), fp_CPUusage);
    sscanf(buf_cpu,"%s%ld%ld%ld%ld%ld%ld%ld",cpu,&user,&nice,&sys,&idle,&iowait,&irq,&softirq);
    total_2 = user + nice + sys + idle + iowait + irq + softirq;
    idle_2 = idle;

    usage = (float)(total_2-total_1-(idle_2-idle_1)) / (total_2-total_1)*100;
    sprintf(cpuInfo, "CPU:%.1f%%", usage);
    fclose(fp_CPUusage);
}

void getRamInfo(char * ramInfo)
{
    struct sysinfo sys_info;
    // CPU占用率
    if (sysinfo(&sys_info) != 0) // sysinfo(&sys_info) != 0 
    {
        perr_d(true,oledLogLevel,"function sysinfo error when called getCPUInfo");
        char *text = "sysinfo-Error";
        ssd1306_drawString(text);
        ssd1306_display();
        delay(500);
    }
    unsigned long totalRam = sys_info.totalram >> 20;
    unsigned long freeRam = sys_info.freeram >> 20;
    sprintf(ramInfo, "RAM:%ld/%ld MB", freeRam, totalRam);
}

void getIPInfo(char * ipInfo)
{
    struct ifaddrs * ifAddrStruct = NULL;
    getifaddrs(&ifAddrStruct);
    void * tmpAddrPtr = malloc(sizeof(struct in_addr));
    while (ifAddrStruct != NULL)
    {
        if (ifAddrStruct->ifa_addr->sa_family == AF_INET)
        {
            // check it is IP4 is a valid IP4 Address
            tmpAddrPtr = &((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
            // memcpy(tmpAddrPtr,&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr,sizeof(struct in_addr));
            char addressBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);

            if (strcmp(ifAddrStruct->ifa_name, "eth0") == 0)
            {
                sprintf(ipInfo, "eth0:%s", addressBuffer);
                break;
            }
            else if (strcmp(ifAddrStruct->ifa_name, "wlan0") == 0)
            {
                sprintf(ipInfo, "wlan0:%s", addressBuffer);
                break;
            }
        }
        ifAddrStruct = ifAddrStruct->ifa_next;
    }
}

void getDiskInfo(char * diskInfo)
{
    struct statfs disk_info;
    statfs("/", &disk_info);
    unsigned long long totalBlocks = disk_info.f_bsize;
    unsigned long long totalSize = totalBlocks * disk_info.f_blocks;
    size_t mbTotalsize = totalSize >> 20;
    unsigned long long freeDisk = disk_info.f_bfree * totalBlocks;
    size_t mbFreedisk = freeDisk >> 20;
    sprintf(diskInfo, "Disk:%ld/%ldMB", mbFreedisk, mbTotalsize);
}

void default_show()
{
    ssd1306_clearDisplay();

    char CPUInfo[MAX_SIZE] = {0};
    char CPUTemp[MAX_SIZE] = {0};
    char RamInfo[MAX_SIZE] = {0};
    char DiskInfo[MAX_SIZE] = {0};
    char IPInfo[MAX_SIZE] = {0};

    getCPUInfo(CPUInfo);
    sprintf(CPUTemp,"Temp:%.1fC", readTemp());
    getRamInfo(RamInfo);
    getDiskInfo(DiskInfo);
    getIPInfo(IPInfo);


    ssd1306_drawText(0, 0, CPUInfo);
    ssd1306_drawText(56, 0, CPUTemp);
    ssd1306_drawText(0, 8, RamInfo);
    ssd1306_drawText(0, 16, DiskInfo);
    ssd1306_drawText(0, 24, IPInfo);
    ssd1306_display();
}

void * default_show_thread(void * sleep_second)
{
    int slp = 5;
    if(sleep_second != NULL)
        slp = *(int *)sleep_second;
    while(1)
    {
        default_show();
        sleep(slp);
    }
    return NULL;
}